package com.lagou.sqlSession;

import com.lagou.config.BoundSql;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MapStatement;
import com.lagou.utils.GenericTokenParser;
import com.lagou.utils.ParameterMapping;
import com.lagou.utils.ParameterMappingTokenHandler;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jsy
 * @description: TODO
 * @date 2021/8/28 20:19
 */
public class SimpleExecutor implements Executor {

    @Override
    public <E> List<E> query(Configuration configuration, MapStatement mapStatement, Object... param) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, IntrospectionException, InvocationTargetException {
        // 1.获取连接
        Connection connection = configuration.getDataSource().getConnection();
        // 2.select * from user where id = #{id} and username = #{username}
        String sql = mapStatement.getSql();
        //对sql进行处理 BoundSql
        BoundSql boundsql = getBoundSql(sql);
        // select * from where id = ? and username = ?
        String finalSql = boundsql.getSqlText();
        PreparedStatement preparedStatement = connection.prepareStatement(finalSql);
        //获取传入参数类型
        String paramterType = mapStatement.getParamterType();
        Class<?> classOf = getClassType(paramterType);
        List<ParameterMapping> parameterMappingList = boundsql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String name = parameterMapping.getContent();
            //反射
            Field declaredField = classOf.getDeclaredField(name);
            declaredField.setAccessible(true);
            //参数的值
            Object o = declaredField.get(param[0]);
            //给占位符赋值
            preparedStatement.setObject(i + 1, o);
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = mapStatement.getResultType();
        Class<?> resultTypeClassType = getClassType(resultType);
        ArrayList<Object> objects = new ArrayList<Object>();
        while (resultSet.next()) {
            Object o = resultTypeClassType.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            //列个数
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                //属性名
                String columnName = metaData.getColumnName(i);
                //属性值
                Object value = resultSet.getObject(columnName);
                //创建属性描述器，为属性生成读写方法
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClassType);
                //获取写方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //向类中写入值
                writeMethod.invoke(o, value);
            }
            objects.add(o);
        }
        return (List<E>) objects;

    }

    @Override
    public int executeQuery(Configuration configuration, MapStatement mapStatement, Object... param) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        // 1.获取连接
        Connection connection = configuration.getDataSource().getConnection();
        String sql = mapStatement.getSql();
        // 2.对sql进行处理 BoundSql
        BoundSql boundsql = getBoundSql(sql);
        String finalSql = boundsql.getSqlText();
        PreparedStatement preparedStatement = connection.prepareStatement(finalSql);
        //3. 获取传入参数类型
        String paramterType = mapStatement.getParamterType();
        Class<?> classOf = getClassType(paramterType);
        List<ParameterMapping> parameterMappingList = boundsql.getParameterMappingList();
        //4.删除单个参数，增加更改对象形式。单个参数反射会找不到类，所以单个参数表示删除直接赋值
        if (parameterMappingList.size()==1){
            preparedStatement.setObject(1,param[0]);
        }else {
            for (int i = 0; i < parameterMappingList.size(); i++) {
                ParameterMapping parameterMapping = parameterMappingList.get(i);
                String name = parameterMapping.getContent();
                //反射
                Field declaredField = classOf.getDeclaredField(name);
                declaredField.setAccessible(true);
                //参数的值
                Object o = declaredField.get(param[0]);
                //给占位符赋值
                preparedStatement.setObject(i + 1, o);
            }
        }
        //直接返回受影响得行数
        return preparedStatement.executeUpdate();

    }
    private BoundSql getBoundSql(String sql) {
        //标记处理类：主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解 析工 作，其中TokenHandler主要完成处理
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        //GenericTokenParser :通用的标记解析器，完成了代码片段中的占位符的解析，然后再根 据 给定的标记处理器(TokenHandler)来进行表达式的处理 //三个参数：分别为openToken (开始标记)、closeToken (结束标记)、handler (标记处 理器)
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        String parse = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(parse, parameterMappings);
        return boundSql;
    }

    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        if (paramterType != null) {
            Class<?> asClass = Class.forName(paramterType);
            return asClass;
        }
        return null;
    }
}